package com.ds.infrastructure.hyperspace.console.service.impl;

import com.ds.infrastructure.hyperspace.console.common.methodlock.MethodLock;
import com.ds.infrastructure.hyperspace.console.common.methodlock.MethodLockId;
import com.ds.infrastructure.hyperspace.console.config.proxy.ProxyMetricsConfiguration;
import com.ds.infrastructure.hyperspace.console.constants.MethodLockConstant;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbDeployNodeEnum;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbMetricsTaskEnum;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbNodeMetricsEnum;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbPublicEnum;
import com.ds.infrastructure.hyperspace.console.entity.page.TbPageWhere;
import com.ds.infrastructure.hyperspace.console.entity.table.*;
import com.ds.infrastructure.hyperspace.console.exceptions.HyperspaceException;
import com.ds.infrastructure.hyperspace.console.service.inf.*;
import com.ds.infrastructure.hyperspace.console.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.http.client.fluent.Request;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

/**
 * @author: yaozhendong
 * @create: 2019-10-31 14:28
 **/
@Slf4j
@Service
public class MetricsManageService implements IMetricsManageService {
    @Autowired
    IStageService stageService;
    @Autowired
    IDeployInstallTaskService iDeployInstallTaskService;
    @Autowired
    IDeployManageService iDeployManageService;
    @Resource
    ProxyMetricsConfiguration proxyMetricsConfiguration;
    @Autowired
    INodeMetricsService iNodeMetricsService;
    @Autowired
    IMetricsTaskService iMetricsTaskService;
    @Autowired
    IDeployNodeService iDeployNodeService;
    @Autowired
    INodeMetricsAggregationService iNodeMetricsAggregationService;
    @Autowired
    IEnvironmentService iEnvironmentService;
    @Autowired
    IStageService iStageService;
    @Autowired
    IDeployConfigService iDeployConfigService;
    @Autowired
    IContainerActiveConfigService iContainerActiveConfigService;

    private static final String REQUEST_ERROR_TAG = "REQUEST_ERROR_TAG";

    @Override
    public void crawlMetrics() {
        Date taskExecuteTime = new Date();
        log.info("执行指标抓取任务，ExecuteTime=" + MetricsUtil.dateToTaskExecuteTime(taskExecuteTime));
        List<TbStage> tbStageList = getStageList();
        for (TbStage tbStage : tbStageList) {
            getStageMetrics(tbStage, taskExecuteTime);
        }
    }

    private void getStageMetrics(TbStage tbStage, Date taskExecuteTime) {
        TbDeployInstallTask tbDeployInstallTask = iDeployInstallTaskService.selectLastOneForExecuteSuccess(tbStage.getId(), tbStage.getEnvironmentId());
        if (tbDeployInstallTask == null) {
            return;
        }
        List<TbDeployNode> tbDeployNodeList = iDeployManageService.getDeployNode(tbDeployInstallTask.getId(), true);
        if (tbDeployNodeList == null || tbDeployNodeList.isEmpty()) {
            return;
        }
        TbEnvironment tbEnvironment = iEnvironmentService.get(tbStage.getEnvironmentId());
        if (tbEnvironment == null || TbPublicEnum.GMD_IS_DEL.YES.code.equals(tbEnvironment.getGmtIsDeleted())) {
            return;
        }
        String taskInfo = String.format("Task info:EnvironmentName:%s;EnvironmentId:%s;StageName:%s;StageId:%s;", tbEnvironment.getEnvironmentName(), tbEnvironment.getId(), tbStage.getStageName(), tbStage.getId());
        Long metricsTaskId = saveMetricsTask(tbStage.getId(), tbStage.getEnvironmentId(), tbDeployInstallTask.getId(), taskExecuteTime);
        Map<String, List<TbNodeMetrics>> preOneMinuteNodeMetricsMap = getPreOneMinuteNodeMetricsList(tbStage.getId(), tbStage.getEnvironmentId(), tbDeployInstallTask.getId(), taskExecuteTime);
        tbDeployNodeList = tbDeployNodeList.stream().filter(StreamUtil.distinctByKey(TbDeployNode::getHost)).collect(Collectors.toList());
        tbDeployNodeList.forEach(node -> pullMetrics(taskInfo, tbStage.getId(), node, metricsTaskId, taskExecuteTime, preOneMinuteNodeMetricsMap));
        updateMetricsTaskForState(metricsTaskId, TbMetricsTaskEnum.EXECUTE_STATE.CRAWL, null);
    }

    private Map<String, List<TbNodeMetrics>> getPreOneMinuteNodeMetricsList(Long stageId, Long environmentId, Long deployInstallTaskId, Date taskExecuteTime) {
        TbMetricsTask preMinuteMetricsTask = getPreMinuteMetricsTask(stageId, environmentId, deployInstallTaskId, taskExecuteTime);
        if (preMinuteMetricsTask == null) {
            return Collections.emptyMap();
        }
        TbNodeMetrics where = new TbNodeMetrics();
        where.setMetricsTaskId(preMinuteMetricsTask.getId());
        List<TbNodeMetrics> tbNodeMetricsList = iNodeMetricsService.getList(where, null, TbPageWhere.newPage4All());
        return tbNodeMetricsList.stream().collect(Collectors.groupingBy(TbNodeMetrics::getHost));
    }

    private void updateMetricsTaskForState(Long metricsTaskId, TbMetricsTaskEnum.EXECUTE_STATE executeState, TbPublicEnum.TASK_COMPLETE_STATE completeState) {
        TbMetricsTask tbMetricsTask = new TbMetricsTask();
        tbMetricsTask.setId(metricsTaskId);
        if (executeState != null) {
            tbMetricsTask.setExecuteState(executeState.code);
        }
        if (completeState != null) {
            tbMetricsTask.setCompleteState(completeState.value);
        }
        iMetricsTaskService.update(tbMetricsTask);
    }

    private Long saveMetricsTask(Long stageId, Long environmentId, Long deployInstallTaskId, Date taskExecuteTime) {
        TbMetricsTask tbMetricsTask = new TbMetricsTask();
        tbMetricsTask.setStageId(stageId);
        tbMetricsTask.setEnvironmentId(environmentId);
        tbMetricsTask.setDeployInstallTaskId(deployInstallTaskId);
        tbMetricsTask.setExecuteTime(MetricsUtil.dateToTaskExecuteTime(taskExecuteTime));
        tbMetricsTask.setExecuteState(TbMetricsTaskEnum.EXECUTE_STATE.INIT.code);
        tbMetricsTask.setCompleteState(TbPublicEnum.TASK_COMPLETE_STATE.INIT.value);
        tbMetricsTask.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        iMetricsTaskService.save(tbMetricsTask);
        return tbMetricsTask.getId();
    }

    private TbMetricsTask getPreMinuteMetricsTask(Long stageId, Long environmentId, Long deployInstallTaskId, Date taskExecuteTime) {
        TbMetricsTask where = new TbMetricsTask();
        where.setStageId(stageId);
        where.setEnvironmentId(environmentId);
        where.setDeployInstallTaskId(deployInstallTaskId);
        where.setCompleteState(TbPublicEnum.TASK_COMPLETE_STATE.COMPLETE.value);
        where.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        Long preOneMinuteExecuteTime = MetricsUtil.dateToTaskExecuteTime(DateUtils.addMinutes(taskExecuteTime, -1));
        where.setExecuteTime(preOneMinuteExecuteTime);
        return iMetricsTaskService.selectLastOne(where, null);
    }


    private static final String REQUEST_UUID_MESSAGE = "REQUEST UUID:";

    private void pullMetrics(String taskInfo, Long stageId, TbDeployNode node, Long metricsTaskId, Date taskExecuteTime, Map<String, List<TbNodeMetrics>> preOneMinuteNodeMetricsMap) {
        String requestUUID = UUID.randomUUID().toString();
        String requestUrl = proxyMetricsConfiguration.getProtocol() + node.getHost() + ":" + proxyMetricsConfiguration.getPort();
        log.info(REQUEST_UUID_MESSAGE + requestUUID + ";" + requestUrl);
        String responseBody = null;
        TbDeployNodeEnum.HEALTH_STATE healthState = TbDeployNodeEnum.HEALTH_STATE.SUCCESS;
        try {
            responseBody = HttpUtil.getRequest(requestUrl).execute().returnContent().asString();
            log.info(REQUEST_UUID_MESSAGE + requestUUID + ";" + responseBody);
            //解析responseBody
            List<TbNodeMetrics> tbNodeMetricsList = extractMetrics(taskInfo, stageId, node, responseBody, requestUUID, metricsTaskId, taskExecuteTime);
            revisedLeTagData(tbNodeMetricsList);
            if (!preOneMinuteNodeMetricsMap.isEmpty()) {
                addMetricsPreValueAndMetricsRealValueInfo(tbNodeMetricsList, preOneMinuteNodeMetricsMap.get(node.getHost()));
            }
            iNodeMetricsService.insertList(tbNodeMetricsList);
        } catch (Exception e) {
            String error = String.format("%s MetricsTaskId:%s;Node Host:%s;Node Host Group:%s;RequestUUID:%s;", taskInfo, metricsTaskId, node.getHost(), node.getHostGroupName(), requestUUID);
            log.error("抓取网关指标数据请求失败:" + System.lineSeparator() + error, e);
            healthState = TbDeployNodeEnum.HEALTH_STATE.FAIL;
        }
        iDeployNodeService.updateHealthState(node.getDeployTaskId(), node.getHost(), healthState);
    }

    /**
     * 校正le_tag属性的数据
     * 数据分布桶的值是累加值，区间实际数据：当前区间值-下个区间值
     *
     * @param tbNodeMetricsList
     */
    private void revisedLeTagData(List<TbNodeMetrics> tbNodeMetricsList) {
        List<TbNodeMetrics> requestSecondBucketMetricsList = tbNodeMetricsList.stream()
                .filter(item -> TbNodeMetricsEnum.METRICS_KEY.HYPERSPACE_REQUEST_SECONDS_BUCKET.key.equals(item.getMetricsKey())).collect(Collectors.toList());
        requestSecondBucketMetricsList.stream().collect(Collectors.groupingBy(TbNodeMetrics::getServiceName));
        List<TbNodeMetrics> requestSecondBucketMetricsListCopy = ListUtil.deepCopy(requestSecondBucketMetricsList, TbNodeMetrics.class);
        for (TbNodeMetrics currentNodeMetrics : requestSecondBucketMetricsList) {
            TbNodeMetricsEnum.HYPERSPACE_REQUEST_SECONDS_BUCKET_LE_TAG nextLeTag = TbNodeMetricsEnum.HYPERSPACE_REQUEST_SECONDS_BUCKET_LE_TAG.getNextLeTag(currentNodeMetrics.getServiceExtend2());
            if (nextLeTag == null) {
                continue;
            }
            Optional<TbNodeMetrics> nextNodeMetricsOptional = requestSecondBucketMetricsListCopy.stream()
                    .filter(item -> currentNodeMetrics.getServiceName().equals(item.getServiceName()) &&
                            currentNodeMetrics.getServiceExtend1().equals(item.getServiceExtend1()) &&
                            nextLeTag.key.equals(item.getServiceExtend2())).findFirst();
            if (!nextNodeMetricsOptional.isPresent()) {
                continue;
            }
            Long metricsValue = currentNodeMetrics.getMetricsValue() - nextNodeMetricsOptional.get().getMetricsValue();
            currentNodeMetrics.setMetricsValue(metricsValue);
        }
    }

    private void addMetricsPreValueAndMetricsRealValueInfo(List<TbNodeMetrics> nodeMetricsList, List<TbNodeMetrics> preOneMinuteNodeMetricsList) {
        if (preOneMinuteNodeMetricsList == null) {
            return;
        }
        for (TbNodeMetrics tbNodeMetrics : nodeMetricsList) {
            Optional<TbNodeMetrics> preOneMinuteNodeMetricsOptional = preOneMinuteNodeMetricsList.stream().filter(item ->
                    tbNodeMetrics.getMetricsKey().equals(item.getMetricsKey()) &&
                            tbNodeMetrics.getServiceName().equals(item.getServiceName()) &&
                            isEqualsServiceExtend(tbNodeMetrics.getServiceExtend1(), item.getServiceExtend1()) &&
                            isEqualsServiceExtend(tbNodeMetrics.getServiceExtend2(), item.getServiceExtend2())).findFirst();
            if (!preOneMinuteNodeMetricsOptional.isPresent()) {
                continue;
            }
            TbNodeMetricsEnum.METRICS_KEY metricsKeyEnum = TbNodeMetricsEnum.METRICS_KEY.toEnum(tbNodeMetrics.getMetricsKey());
            if (metricsKeyEnum == null) {
                continue;
            }
            TbNodeMetrics preOneMinuteNodeMetrics = preOneMinuteNodeMetricsOptional.get();
            Long metricsRealValue = metricsKeyEnum.aggregateFunction.function(tbNodeMetrics.getMetricsValue(), preOneMinuteNodeMetrics.getMetricsValue());
            if (metricsRealValue >= 0) {
                tbNodeMetrics.setMetricsPreValue(preOneMinuteNodeMetrics.getMetricsValue());
                tbNodeMetrics.setMetricsRealValue(metricsRealValue);
            }
        }
    }

    private boolean isEqualsServiceExtend(String serviceExtend1, String serviceExtend2) {
        if (serviceExtend1 == null && serviceExtend2 == null) {
            return true;
        }
        if (serviceExtend1 != null) {
            return serviceExtend1.equals(serviceExtend2);
        }
        return false;
    }

    private List<TbNodeMetrics> extractMetrics(String taskInfo, Long stageId, TbDeployNode node, String responseBody, String requestUUID, Long metricsTaskId, Date taskExecuteTime) {
        List<String> metricsList = parseBody(responseBody);
        if (metricsList.isEmpty()) {
            String error = String.format("%s MetricsTaskId:%s;Node Host:%s;Node Host Group:%s;RequestUUID:%s;", taskInfo, metricsTaskId, node.getHost(), node.getHostGroupName(), requestUUID);
            log.error("ResponseBody解析失败:" + System.lineSeparator() + error + System.lineSeparator() + responseBody);
            return Collections.emptyList();
        }
        String pattern = "([^{]+)\\{([^}]+)}[\\s]+([\\d\\\\.E]+)$";
        List<TbNodeMetrics> tbNodeMetricsList = new ArrayList<>();
        for (String item : metricsList) {
            Matcher mc = RegexUtil.getMatcher(pattern, item);
            String metricsKey = null;
            String metricsValueField = null;
            String serviceField = null;
            if (!mc.find() || mc.groupCount() != 3) {
                continue;
            }
            metricsKey = mc.group(1);
            serviceField = mc.group(2);
            metricsValueField = mc.group(3);
            boolean isNum = NumberUtils.isCreatable(metricsValueField);
            if (!isNum) {
                throw new HyperspaceException("metrics value is not number,metrics record:" + item);
            }
            BigDecimal metricsValue = NumberUtils.createBigDecimal(metricsValueField);
            TbNodeMetrics tbNodeMetrics = new TbNodeMetrics();
            tbNodeMetrics.setStageId(stageId);
            tbNodeMetrics.setDeployTaskId(node.getDeployTaskId());
            tbNodeMetrics.setMetricsTaskId(metricsTaskId);
            tbNodeMetrics.setHost(node.getHost());
            tbNodeMetrics.setMetricsKey(metricsKey);
            tbNodeMetrics.setMetricsPreValue(TbPublicEnum.METRICS_VALUE.DEFAULT.value);
            tbNodeMetrics.setMetricsRealValue(TbPublicEnum.METRICS_VALUE.DEFAULT.value);
            tbNodeMetrics.setMetricsValue(metricsValue.longValue());
            tbNodeMetrics.setExecuteTime(MetricsUtil.dateToTaskExecuteTime(taskExecuteTime));
            tbNodeMetrics.setGmtCreate(taskExecuteTime);
            tbNodeMetrics.setRequestUuid(requestUUID);
            addMetricsServiceInfo(serviceField, tbNodeMetrics);
            tbNodeMetricsList.add(tbNodeMetrics);
        }
        return tbNodeMetricsList;
    }

    private void addMetricsServiceInfo(String serviceField, TbNodeMetrics tbNodeMetrics) {
        String[] itemArr = serviceField.split(",");
        for (int i = 0; i < itemArr.length; i++) {
            String value = getValueBetweenDoubleQuotes(itemArr[i]);
            if (i == 0) {
                tbNodeMetrics.setServiceName(value);
            }
            if (i == 1) {
                tbNodeMetrics.setServiceExtend1(value);
            }
            if (i == 2) {
                tbNodeMetrics.setServiceExtend2(value);
            }
        }
    }

    private String getValueBetweenDoubleQuotes(String value) {
        String quote = "\"";
        value = value.substring(value.indexOf(quote) + 1, value.lastIndexOf(quote)).trim();
        return value;
    }

    private List<String> parseBody(String responseBody) {
        List<String> metricsList = new ArrayList<>();
        String[] itemArr = StringUtils.split(responseBody, "[\r\n]");
        for (String item : itemArr) {
            if (StringUtils.isBlank(item) || !RegexUtil.regex("^hyperspace_", item)) {
                continue;
            }
            metricsList.add(item);
        }
        return metricsList;
    }

    private List<TbStage> getStageList() {
        TbStage where = new TbStage();
        where.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        return stageService.getList(where, null, TbPageWhere.newPage4All());
    }

    //=====================================================================================================
    @Override
    public void aggregationMetrics() {
        List<TbMetricsTask> tbMetricsTaskList = getAllNoAggregationMetricsTask();
        for (TbMetricsTask tbMetricsTask : tbMetricsTaskList) {
            aggregationMetricsByTaskId(tbMetricsTask);
            updateMetricsTaskForState(tbMetricsTask.getId(), TbMetricsTaskEnum.EXECUTE_STATE.AGGREGATION, TbPublicEnum.TASK_COMPLETE_STATE.COMPLETE);
        }

    }


    private void aggregationMetricsByTaskId(TbMetricsTask metricsTask) {
        TbNodeMetrics where = new TbNodeMetrics();
        where.setMetricsTaskId(metricsTask.getId());
        List<TbNodeMetrics> tbNodeMetricsList = iNodeMetricsService.getList(where, null, TbPageWhere.newPage4All());
        if (tbNodeMetricsList == null || tbNodeMetricsList.isEmpty()) {
            return;
        }
        //
        addErrorRequestTag(tbNodeMetricsList);
        //
        Map<String, List<TbNodeMetrics>> tbNodeMetricsListForHostMap = tbNodeMetricsList.stream().collect(Collectors.groupingBy(TbNodeMetrics::getHost));
        List<TbNodeMetricsAggregation> currentTbNodeMetricsAggregationList = new ArrayList<>();
        for (Map.Entry<String, List<TbNodeMetrics>> entry : tbNodeMetricsListForHostMap.entrySet()) {
            //统计请求数
            statisticsRequestCount(TbNodeMetricsEnum.METRICS_KEY.HYPERSPACE_REQUEST_SECONDS_COUNT, entry.getKey(), entry.getValue(), metricsTask, currentTbNodeMetricsAggregationList);
            //统计错误数
            statisticsRequestErrorCount(entry.getKey(), entry.getValue(), metricsTask, currentTbNodeMetricsAggregationList);
        }
        //
        List<TbNodeMetricsAggregation> preMinuteTbNodeMetricsAggregationList = preMinuteNodeMetricsAggregationData(metricsTask);
        mergeNodeMetricsAggregatedData(currentTbNodeMetricsAggregationList, preMinuteTbNodeMetricsAggregationList);
        if (currentTbNodeMetricsAggregationList.isEmpty()) {
            return;
        }
        iNodeMetricsAggregationService.insertList(currentTbNodeMetricsAggregationList);
    }

    private void statisticsRequestErrorCount(String host, List<TbNodeMetrics> tbNodeMetricsList, TbMetricsTask metricsTask, List<TbNodeMetricsAggregation> tbNodeMetricsAggregationList) {
        List<TbNodeMetrics> requestErrorMetricsList = tbNodeMetricsList.stream()
                .filter(item -> TbNodeMetricsEnum.METRICS_KEY.HYPERSPACE_REQUESTS_TOTAL.key.equals(item.getMetricsKey()) &&
                        REQUEST_ERROR_TAG.equals(item.getServiceExtend2())).collect(Collectors.toList());
        toNodeMetricsAggregation(TbNodeMetricsEnum.METRICS_KEY.HYPERSPACE_ERRORS_TOTAL, host, metricsTask, tbNodeMetricsAggregationList, requestErrorMetricsList);
    }

    private void addErrorRequestTag(List<TbNodeMetrics> tbNodeMetricsList) {
        List<TbNodeMetrics> requestTotalMetricsList = tbNodeMetricsList.stream()
                .filter(item -> TbNodeMetricsEnum.METRICS_KEY.HYPERSPACE_REQUESTS_TOTAL.key.equals(item.getMetricsKey())).collect(Collectors.toList());

        for (TbNodeMetrics tbNodeMetrics : requestTotalMetricsList) {
            if ("-1".equals(tbNodeMetrics.getServiceExtend2())) {
                tbNodeMetrics.setServiceExtend1(TbNodeMetricsEnum.ENDPOINT_TYPE_TAG.GATEWAY.key);
                tbNodeMetrics.setServiceExtend2(REQUEST_ERROR_TAG);
                continue;
            }
            if (Integer.parseInt(tbNodeMetrics.getServiceExtend2()) >= 400) {
                tbNodeMetrics.setServiceExtend1(TbNodeMetricsEnum.ENDPOINT_TYPE_TAG.TARGET.key);
                tbNodeMetrics.setServiceExtend2(REQUEST_ERROR_TAG);
            }
        }
    }

    private void mergeNodeMetricsAggregatedData(List<TbNodeMetricsAggregation> currentTbNodeMetricsAggregationList, List<TbNodeMetricsAggregation> preMinuteTbNodeMetricsAggregationList) {
        if (preMinuteTbNodeMetricsAggregationList == null || preMinuteTbNodeMetricsAggregationList.isEmpty()) {
            return;
        }
        for (TbNodeMetricsAggregation currentNodeMetrics : currentTbNodeMetricsAggregationList) {
            Optional<TbNodeMetricsAggregation> preMinuteNodeMetricsOptional = preMinuteTbNodeMetricsAggregationList.stream().filter(item ->
                    currentNodeMetrics.getHost().equals(item.getHost()) &&
                            currentNodeMetrics.getMetricsKey().equals(item.getMetricsKey()) &&
                            currentNodeMetrics.getEndpointType().equals(item.getEndpointType())).findFirst();
            if (!preMinuteNodeMetricsOptional.isPresent()) {
                continue;
            }
            TbNodeMetricsAggregation preMinuteNodeMetrics = preMinuteNodeMetricsOptional.get();
            Long realValue = TbNodeMetricsEnum.METRICS_KEY.toEnum(currentNodeMetrics.getMetricsKey())
                    .aggregateFunction.function(currentNodeMetrics.getMetricsValue(), preMinuteNodeMetrics.getMetricsValue());
            if (realValue >= 0) {
                currentNodeMetrics.setMetricsPreValue(preMinuteNodeMetrics.getMetricsValue());
                currentNodeMetrics.setMetricsRealValue(realValue);
            }
        }
    }

    private List<TbNodeMetricsAggregation> preMinuteNodeMetricsAggregationData(TbMetricsTask metricsTask) {
        Long preMinuteExecuteTime = MetricsUtil.getPreOneMinuteExecuteTime(metricsTask.getExecuteTime());
        TbMetricsTask where4MetricsTask = new TbMetricsTask();
        where4MetricsTask.setStageId(metricsTask.getStageId());
        where4MetricsTask.setEnvironmentId(metricsTask.getEnvironmentId());
        where4MetricsTask.setDeployInstallTaskId(metricsTask.getDeployInstallTaskId());
        where4MetricsTask.setExecuteTime(preMinuteExecuteTime);
        where4MetricsTask.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        TbMetricsTask preMinuteTbMetricsTask = iMetricsTaskService.selectLastOne(where4MetricsTask, null);
        if (preMinuteTbMetricsTask == null) {
            return Collections.emptyList();
        }
        //拉取最新的前一分钟的指标数据，PS:程序出错时有可能同一分钟抓取多条指标数据
        TbNodeMetricsAggregation where4NodeMetricsAggregation = new TbNodeMetricsAggregation();
        where4NodeMetricsAggregation.setMetricsTaskId(preMinuteTbMetricsTask.getId());
        return iNodeMetricsAggregationService.getList(where4NodeMetricsAggregation, null, TbPageWhere.newPage4All());
    }


    private void statisticsRequestCount(TbNodeMetricsEnum.METRICS_KEY metricsKey, String host, List<TbNodeMetrics> tbNodeMetricsList, TbMetricsTask metricsTask, List<TbNodeMetricsAggregation> tbNodeMetricsAggregationList) {
        List<TbNodeMetrics> hyperspaceMetrics = tbNodeMetricsList.stream().filter(item -> metricsKey.key.equals(item.getMetricsKey())).collect(Collectors.toList());
        toNodeMetricsAggregation(metricsKey, host, metricsTask, tbNodeMetricsAggregationList, hyperspaceMetrics);
    }

    private void toNodeMetricsAggregation(TbNodeMetricsEnum.METRICS_KEY metricsKey, String host, TbMetricsTask metricsTask, List<TbNodeMetricsAggregation> tbNodeMetricsAggregationList, List<TbNodeMetrics> hyperspaceMetrics) {
        if (hyperspaceMetrics.isEmpty()) {
            return;
        }
        Map<String, LongSummaryStatistics> sumCollect = hyperspaceMetrics.stream().collect(Collectors.groupingBy(TbNodeMetrics::getServiceExtend1, Collectors.summarizingLong(TbNodeMetrics::getMetricsValue)));
        for (Map.Entry<String, LongSummaryStatistics> entry : sumCollect.entrySet()) {
            TbNodeMetricsAggregation tbNodeMetricsAggregation = new TbNodeMetricsAggregation();
            tbNodeMetricsAggregation.setStageId(metricsTask.getStageId());
            tbNodeMetricsAggregation.setDeployTaskId(metricsTask.getDeployInstallTaskId());
            tbNodeMetricsAggregation.setMetricsTaskId(metricsTask.getId());
            tbNodeMetricsAggregation.setMetricsKey(metricsKey.key);
            tbNodeMetricsAggregation.setHost(host);
            tbNodeMetricsAggregation.setMetricsValue(entry.getValue().getSum());
            tbNodeMetricsAggregation.setMetricsPreValue(TbPublicEnum.METRICS_VALUE.DEFAULT.value);
            tbNodeMetricsAggregation.setMetricsRealValue(TbPublicEnum.METRICS_VALUE.DEFAULT.value);
            tbNodeMetricsAggregation.setEndpointType(entry.getKey());
            tbNodeMetricsAggregation.setExecuteTime(metricsTask.getExecuteTime());
            tbNodeMetricsAggregation.setGmtCreate(metricsTask.getGmtCreate());
            tbNodeMetricsAggregationList.add(tbNodeMetricsAggregation);
        }
    }

    private List<TbMetricsTask> getAllNoAggregationMetricsTask() {
        TbMetricsTask where = new TbMetricsTask();
        where.setExecuteState(TbMetricsTaskEnum.EXECUTE_STATE.CRAWL.code);
        where.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        where.setCompleteState(TbPublicEnum.TASK_COMPLETE_STATE.INIT.value);
        return iMetricsTaskService.getList(where, null, TbPageWhere.newPage4All());
    }

    @Override
    public void cleanMetrics() {
        Date now = new Date();
        Long executeTime4EndTime = MetricsUtil.dateToTaskExecuteTime(DateUtils.addDays(now, -1));
        iNodeMetricsAggregationService.clean(executeTime4EndTime);
        iNodeMetricsService.clean(executeTime4EndTime);
        iMetricsTaskService.clean(executeTime4EndTime);
    }

    @Override
    @MethodLock(name = MethodLockConstant.SCHEDULE_FOR_METRICS_JOB_METHOD)
    public void cleanMetricsJobWithMethodLockId(MethodLockId methodLockId) {
        cleanMetrics();
    }

    @Override
    @MethodLock(name = MethodLockConstant.SCHEDULE_FOR_METRICS_JOB_METHOD)
    public void crawlMetricsJobWithMethodLockId(MethodLockId methodLockId) {
        crawlMetrics();
        aggregationMetrics();
    }
}
